/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package util;


import java.io.Serializable;


/**
 *
 * @author grupo 02
 */


public class Instruction implements Serializable {

    //codigos de tipos de operaciones
    // mascara "11110000"
    public static final int OPPILA       =  0;     // 0000
    public static final int OPARIT       =  16;    // 0001
    public static final int OPLOG        =  32;    // 0010
    public static final int OPSALT       =  48;    // 0011
    public static final int OPMISC       =  112;   // 0111

    //operaciones pila-memoria "0000xxxx"
    //codigo aplicada la mascara "00001111"
    public static final int APILA        = 0;
    public static final int APILA_DIR    = 1;
    public static final int DESAPILA_DIR = 2;
    public static final int DESAPILA_IND = 3;
    public static final int APILA_IND    = 4;
    public static final int MUEVE        = 5;
    public static final int COPIA        = 6;
    public static final int DESAPILA     = 7;
    public static final int FLIP         = 8;


    //operaciones aritmeticas "0001xxxx"
    //codigo aplicada la mascara "00001111"

    public static final int SUMA  = 0;
    public static final int RESTA = 1;
    public static final int MULT  = 2;
    public static final int DIV   = 3;
    public static final int MOD   = 4;
    public static final int DESPD = 5;
    public static final int DESPI = 6;
    public static final int SIGNO = 7;
    public static final int ABS   = 8;

    //operaciones logicas "0010xxxx"
    //codigo aplicada la mascara "00001111"

    public static final int AND   = 0;
    public static final int OR    = 1;
    public static final int MENOR = 2;
    public static final int MAYOR = 3;
    public static final int MENIG = 4;
    public static final int MAYIG = 5;
    public static final int DIST  = 6;
    public static final int IGUAL = 7;
    public static final int NEG   = 8;

    //operaciones de salto "0011xxxx"
    //codigo aplicada la mascara "00001111"

    public static final int IR_F     = 0;  //salto si cima() = 0
    public static final int IR_A     = 1;  //salto incondicional
    public static final int IR_IND   = 2;  //desapila cima -> PC
    public static final int IR_V     = 3;  //salto si cima() <> 0



    //otras operaciones "0111xxxx"
    //codigo aplicada la mascara "00001111"

    public static final int CFLOAT  = 0;
    public static final int CINT    = 1;
    public static final int CNAT    = 2;
    public static final int CCHAR   = 3;
    public static final int LEER    = 4;
    public static final int ESCR    = 5;
    public static final int DISPOSE = 8;
    public static final int NEW     = 9;
    public static final int SEG     = 10;
    public static final int STOP    = 15;


    // Codificacion completa, tipo de operacion y operacion para utilizarlo
    // desde el analizador sintactico a la hora de generar las instrucciones.

    public static final int code_APILA          = OPPILA+APILA;
    public static final int code_APILA_DIR      = OPPILA+APILA_DIR;
    public static final int code_DESAPILA_DIR   = OPPILA+DESAPILA_DIR;
    public static final int code_DESAPILA_IND   = OPPILA+DESAPILA_IND;
    public static final int code_APILA_IND      = OPPILA+APILA_IND;
    public static final int code_MUEVE          = OPPILA+MUEVE;
    public static final int code_COPIA          = OPPILA+COPIA;
    public static final int code_DESAPILA       = OPPILA+DESAPILA;
    public static final int code_FLIP           = OPPILA+FLIP;

    public static final int code_SUMA  = OPARIT+SUMA;
    public static final int code_RESTA = OPARIT+RESTA;
    public static final int code_MULT  = OPARIT+MULT;
    public static final int code_DIV   = OPARIT+DIV;
    public static final int code_MOD   = OPARIT+MOD;
    public static final int code_DESPD = OPARIT+DESPD;
    public static final int code_DESPI = OPARIT+DESPI;
    public static final int code_SIGNO = OPARIT+SIGNO;
    public static final int code_ABS   = OPARIT+ABS;

    public static final int code_AND   = OPLOG+AND;
    public static final int code_OR    = OPLOG+OR;
    public static final int code_MENOR = OPLOG+MENOR;
    public static final int code_MAYOR = OPLOG+MAYOR;
    public static final int code_MENIG = OPLOG+MENIG;
    public static final int code_MAYIG = OPLOG+MAYIG;
    public static final int code_DIST  = OPLOG+DIST;
    public static final int code_IGUAL = OPLOG+IGUAL;
    public static final int code_NEG   = OPLOG+NEG;

    public static final int code_IR_F    = OPSALT+IR_F;
    public static final int code_IR_V    = OPSALT+IR_V;
    public static final int code_IR_A    = OPSALT+IR_A;
    public static final int code_IR_IND  = OPSALT+IR_IND;

    public static final int code_CFLOAT  = OPMISC+CFLOAT;
    public static final int code_CINT    = OPMISC+CINT;
    public static final int code_CNAT    = OPMISC+CNAT;
    public static final int code_CCHAR   = OPMISC+CCHAR;
    public static final int code_LEER    = OPMISC+LEER;
    public static final int code_ESCR    = OPMISC+ESCR;
    public static final int code_DISPOSE = OPMISC+DISPOSE;
    public static final int code_NEW     = OPMISC+NEW;
    public static final int code_SEG     = OPMISC+SEG;
    public static final int code_STOP    = OPMISC+STOP;





        int  etiqueta;
        byte code;
        String field;


        public byte getCode(){
            return code;
        }

        public int getEtiqueta(){
            return etiqueta;
        }

        public String getField(){
            return field;
        }

        private String translation(byte code){
            int op_type = (code & 112);
            int op_code = (code & 15);

            switch (op_type){

                case OPPILA: switch (op_code){
                                case APILA: return "apila";
                                case APILA_DIR: return "apila_dir";
                                case DESAPILA_DIR: return "desapila_dir";
                                case APILA_IND: return "apila_ind";
                                case DESAPILA_IND: return "desapila_ind";
                                case MUEVE: return "mueve";
                                case COPIA: return "copia";
                                case DESAPILA: return "desapila";
                                case FLIP: return "flip";
                                default:
                                    return "Instruccion no identificada: " + code;

                                }

                case OPARIT: switch (op_code) {
                                case SUMA: return "suma";
                                case RESTA: return "resta";
                                case MULT: return "mult";
                                case DIV: return "div";
                                case MOD: return "mod";
                                case DESPD: return "despD";
                                case DESPI: return "despI";
                                case SIGNO: return "cSigno";
                                case ABS: return "abs";
                                default:
                                    return "Instruccion no identificada: " + code;

                                 }

                case OPLOG:  switch(op_code){
                                case AND: return "and";
                                case OR: return "or";
                                case MENOR: return "menor";
                                case MAYOR: return "mayor";
                                case MENIG: return "menor_igual";
                                case MAYIG: return "mayor_igual";
                                case DIST: return "distinto";
                                case IGUAL: return "igual";
                                default:
                                    return "Instruccion no identificada: " + code;
                                }

                case OPMISC: switch(op_code){
                                case CFLOAT: return "(float)";
                                case CINT: return "(int)";
                                case CNAT: return "(natural)";
                                case CCHAR: return "(char)";
                                case LEER: return "leer";
                                case ESCR: return "escribir";
                                case DISPOSE: return "dispose";
                                case NEW: return "new";
                                case STOP: return "STOP";
                                case SEG: return "seg";
                                default:
                                    return "Instruccion no identificada: " + code;
                                }

                case OPSALT: switch(op_code){
                                case IR_F: return "ir_f";
                                case IR_A: return "ir_a";
                                case IR_V: return "ir_v";
                                case IR_IND: return "ir_ind";
                                default:
                                    return "Instruccion no identificada: " + code;
                                }


            }
            return "Instruccion no identificada: " + code;

        }

        public Instruction(int etiq, byte code, String field){
            this.etiqueta = etiq;
            this.code = code;
            this.field = field;
        }

        @Override
        public String toString(){

            if (field != null)
                return (this.etiqueta + ": " + translation(this.code) +" "+ this.field+"\n");
            else return (this.etiqueta + ": " +  translation(this.code)+"\n");
        }


    }